package com.fattyCorps.common.mgr;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.fattyCorps.common.obj.config.*;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
public class Cfg implements CommandLineRunner {
    private Map<Class, Map<Integer, BaseCfg>> cfgs = new HashMap();

    public enum ECfgFileType {
        Excel,
        Csv
    }

    public void init() {
        load(BehaviorDisplayMould.class, "config/config_behavior_display.csv");
        load(BehaviorEffectMould.class, "config/config_behavior_effect.csv");
        load(BehaviorTrgCndMould.class, "config/config_behavior_trigger_condition.csv");
        load(BuffTypeMould.class, "config/config_buff_type.csv");
        load(EffectTrgCndMould.class, "config/config_effect_trigger_condition.csv");
        load(GlobalMould.class, "config/config_global.csv");
        load(HeroMould.class, "config/config_hero.csv");
        load(ItemMould.class, "config/config_item.csv");
        load(SkillBehaviorMould.class, "config/config_skill_behavior.csv");
        load(SkillBuffMould.class, "config/config_skill_buff.csv");
        load(SkillGroupMould.class, "config/config_skill_group.csv");
        load(SkillMould.class, "config/config_skill.csv");
        load(StarMould.class, "config/config_star.csv");
        load(MainGuanqianMould.class, "config/config_main_guanqia.csv");
        load(PlayerExpMould.class, "config/config_player_exp.csv");
        load(HeroExpMould.class, "config/config_hero_exp.csv");

    }

    public <T extends BaseCfg> void load(Class<T> cls, String filePath) {
        ECfgFileType type = ECfgFileType.Excel;
        if (FileNameUtil.extName(filePath).equals("csv")) {
            type = ECfgFileType.Csv;
        }

        load(cls, filePath, type);
    }

    public <T extends BaseCfg> void load(Class<T> cls, String filePath, ECfgFileType type) {
        if (!cfgs.containsKey(cls)) {
            cfgs.put(cls, new HashMap<>());
        }

        Map<Integer, BaseCfg> cfg = cfgs.get(cls);
        Map<Integer, T> collect = null;

        if (type == ECfgFileType.Excel) {
            File file = FileUtil.file(filePath);
            ExcelReader reader = ExcelUtil.getReader(file);
            collect = reader.readAll(cls).stream().collect(Collectors.toMap(T::getId, v -> v));
        } else {
            final CsvReader reader = CsvUtil.getReader();
            List<T> read = reader.read(ResourceUtil.getUtf8Reader(filePath), cls);
            collect = read.stream().collect(Collectors.toMap(T::getId, v -> v));
        }

        try {
            Iterator<Map.Entry<Integer, T>> iter = collect.entrySet().iterator();
            T defT = cls.newInstance();
            while (iter.hasNext()) {
                Map.Entry<Integer, T> next = iter.next();
                for (Field declaredField : next.getValue().getClass().getDeclaredFields()) {
                    declaredField.setAccessible(true);
                    Object fieldVal = declaredField.get(next.getValue());
                    if (fieldVal == null) {
                        // 设置空属性默认值
                        declaredField.set(next.getValue(), declaredField.get(defT));
                    }
                }
            }

            cfg.putAll(collect);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public <T extends BaseCfg> T getCfgOrNull(Class<T> cls, int key) {
        return getCfg(cls, key, false);
    }

    public <T extends BaseCfg> T getCfg(Class<T> cls, int key) {
        return getCfg(cls, key, true);
    }

    public <T extends BaseCfg> T getCfg(Class<T> cls, int key, boolean te) {
        if (!cfgs.containsKey(cls)) {
            throw new RuntimeException("无法找到" + cls.getSimpleName() + "的配置");
        }

        Map<Integer, BaseCfg> cfg = cfgs.get(cls);

        if (!cfg.containsKey(key)) {
            if (te) {
                throw new RuntimeException("无法找到" + cls.getSimpleName() + "的中，id=" + key + "，的配置");
            }

            return null;
        }

        return (T)cfg.get(key);
    }

    public <T extends BaseCfg> List<T> getCfgAll(Class<T> cls) {
        if (!cfgs.containsKey(cls)) {
            return null;
        }

        return cfgs.get(cls).values().stream().map(x -> (T)x).collect(Collectors.toList());
    }

    @Override
    public void run(String... args) throws Exception {
        init();
        SpringUtil.getBean(GlobalConfig.class).init(this);
    }
}
